package com.reger.web.config;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.AbstractJsonpResponseBodyAdvice;

import com.reger.core.utils.ListUtils;
import com.reger.web.interceptor.LoggerInterceptor;

@Configuration
@EnableConfigurationProperties(WebProperties.class)
public class WebMvcAutoConfiguration extends WebMvcConfigurerAdapter implements EmbeddedServletContainerCustomizer {

	@Autowired private WebProperties webProperties;
	
	@Bean
	public LoggerInterceptor loggerInterceptor(){
		return new LoggerInterceptor(webProperties);
	}
	/**
	 * 请求拦截
	 */
	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		registry.addInterceptor(loggerInterceptor()).addPathPatterns("/**");
		super.addInterceptors(registry);
	}

	@Override
	public void addViewControllers(ViewControllerRegistry registry) {
		super.addViewControllers(registry);
	}

	@Override
	public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
		super.configureDefaultServletHandling(configurer);
	}
	
	@Override
	public void addResourceHandlers(ResourceHandlerRegistry registry) {
		super.addResourceHandlers(registry);
	}

	@Override
	public void customize(ConfigurableEmbeddedServletContainer container) { }

	/**
	 * jsonp支持
	 * 
	 */
	@ControllerAdvice
	@EnableConfigurationProperties(WebProperties.class)
	public static class JsonpResponseBodyAdvice extends AbstractJsonpResponseBodyAdvice {
		public JsonpResponseBodyAdvice(WebProperties webProperties) {
			super(webProperties.getJsonpQueryParamNames());
		}
	}

	@Bean
	public FilterRegistrationBean corsFilter() {
		Map<String, CorsConfiguration> corsConfigurations=new HashMap<String, CorsConfiguration>();
		ListUtils.n(webProperties.getCors()).each(cors->{
			corsConfigurations.put(cors.getPathPattern(), this.corsProperties(cors));
		});
		UrlBasedCorsConfigurationSource configSource=new UrlBasedCorsConfigurationSource();
		configSource.setAlwaysUseFullPath(true);
		configSource.setCorsConfigurations(corsConfigurations);
		FilterRegistrationBean filterRegistration = new FilterRegistrationBean(new CorsFilter(configSource));
		filterRegistration.setEnabled(true);
		filterRegistration.addUrlPatterns("/*");
		return filterRegistration;
	}
	
	private CorsConfiguration corsProperties(CorsProperties cors) {
		CorsConfiguration corsConfiguration = corsConfiguration();
		corsConfiguration.setAllowCredentials(cors.getAllowCredentials());
		corsConfiguration.setAllowedOrigins(cors.getAllowedOrigins());
		corsConfiguration.setAllowedHeaders(ListUtils.n(cors.getAllowedHeaders()).to());
		corsConfiguration.setAllowedMethods(ListUtils.n(cors.getAllowedMethods()).list(m->m.name()).to());
		corsConfiguration.setExposedHeaders(ListUtils.n(cors.getExposedHeaders()).to());
		corsConfiguration.setMaxAge(cors.getMaxAge());
		return corsConfiguration;
	}
	
	private CorsConfiguration corsConfiguration(){
		CorsConfiguration corsConfiguration=new CorsConfiguration(){
			@Override
			public String checkOrigin(String requestOrigin) {
				String origin = super.checkOrigin(requestOrigin);
				if(origin!=null)
					return requestOrigin;
				List<String> origins = getAllowedOrigins();
				for (String pattern : origins) {
					if(requestOrigin.contains(pattern)||pattern.matches(requestOrigin))
						return requestOrigin;
				}
				return null;
			}
		};
		return corsConfiguration;
	}
	
}
